﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using Ventrian.PropertyAgent;
using DotNetNuke.Entities.Modules;
using Aricie.DNN.Modules.ModuleWorkflows.Business;
using Aricie.DNN.Modules.ModuleWorkflows;
using System.Text;
using System.Data.SqlClient;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules.Definitions;
using DotNetNuke.Entities.Users;
using DotNetNuke.Entities.Profile;

namespace Aricie.DNN.Services.Url.FriendlyUrl.Providers.DNN6
{

    public class PropertyAgentUrlRewriter : IModulesListUrlRewriterProvider, ICategoryUrlRewriterProvider, IIsActive
    {


        private const string glbDesktopModuleName = "PropertyAgent";
        private const string glbCustomFieldPrefix = "PACustom";

        private const string glbAgentProfilePrefix = "PAAgentProfile";
        private static PropertyController _PropertyController = new PropertyController();
        private static PropertyTypeController _PropertyTypeController = new PropertyTypeController();
        private static PropertyValueController _PropertyValueController = new PropertyValueController();
        private static CustomFieldController _CustomFieldController = new CustomFieldController();

        private static Dictionary<string, List<CustomFieldInfo>> _CustomFieldIds = new Dictionary<string, List<CustomFieldInfo>>();
        
        List<GroupParamsRewrite> IFriendlyUrlGroupProvider.GetRewrites()
        {
            List<GroupParamsRewrite> toReturn = new List<GroupParamsRewrite>();
            string desc = "Display name of the current Property Agent's entity, filtered according to the general parameters";
            toReturn.Add(new GroupParamsRewrite("DisplayName", desc, RewriteType.SubPath, UrlParam.FromSyntax("propertyid")));

            desc = "Display name of the current Property Agent's Type, filtered according to the general parameters";
            GroupParamsRewrite groupToAdd = new GroupParamsRewrite("PAType", desc, RewriteType.SubPath, UrlParam.FromSyntax("propertyid"));
            groupToAdd.UrlParams[UrlParam.FromSyntax("propertyid")] = ParamNature.NonExclusive | ParamNature.Mandatory;
            toReturn.Add(groupToAdd);

            desc = "Display name of the Property Agent's Type for the current property type, filtered according to the general parameters";
            groupToAdd = new GroupParamsRewrite("PAPropertyTypes", desc, RewriteType.Any, UrlParam.FromSyntax("propertytypeid"));
            toReturn.Add(groupToAdd);

            //declaring existing custom fields as rewrite groups
            this.FillCustomFields();

            foreach (string fieldName in _CustomFieldIds.Keys)
            {
                //
                desc = (_CustomFieldIds[fieldName])[0].CaptionHelp;
                GroupParamsRewrite toAdd = new GroupParamsRewrite(glbCustomFieldPrefix + fieldName, desc, RewriteType.SubPath, UrlParam.FromSyntax("propertyid"));
                toAdd.UrlParams[UrlParam.FromSyntax("propertyid")] = ParamNature.NonExclusive | ParamNature.Mandatory;
                toReturn.Add(toAdd);
            }

            foreach (ProfilePropertyDefinition propDefinition in ProfileController.GetPropertyDefinitionsByPortal(NukeHelper.PortalId))
            {
                GroupParamsRewrite toAdd = new GroupParamsRewrite(glbAgentProfilePrefix + propDefinition.PropertyName, "", RewriteType.SubPath, UrlParam.FromSyntax("propertyid"));
                toAdd.UrlParams[UrlParam.FromSyntax("propertyid")] = ParamNature.NonExclusive | ParamNature.Mandatory;
                toReturn.Add(toAdd);
            }

            return toReturn;
        }

        //Dans le cas ou le module est encapsulé, il n'est pas possible de retrouver les modules, il doivent donc provenir des parametres
        List<GroupParamsRewrite> IModulesListUrlRewriterProvider.GetRewrites(List<int> modulesIds)
        {
            List<GroupParamsRewrite> toReturn = new List<GroupParamsRewrite>();
            string desc = "Display name of the current Property Agent's entity, filtered according to the general parameters";
            toReturn.Add(new GroupParamsRewrite("DisplayName", desc, RewriteType.SubPath, UrlParam.FromSyntax("propertyid")));

            desc = "Display name of Property Agent's Type for the current property, filtered according to the general parameters";
            GroupParamsRewrite groupToAdd = new GroupParamsRewrite("PAType", desc, RewriteType.Any, UrlParam.FromSyntax("propertyid"));
            groupToAdd.UrlParams[UrlParam.FromSyntax("propertyid")] = ParamNature.NonExclusive | ParamNature.Mandatory;

            toReturn.Add(groupToAdd);

            desc = "Display name of the Property Agent's Type for the current property type, filtered according to the general parameters";
            groupToAdd = new GroupParamsRewrite("PAPropertyTypes", desc, RewriteType.Any, UrlParam.FromSyntax("propertytypeid"));
            toReturn.Add(groupToAdd);


            //declaring existing custom fields as rewrite groups
            this.FillCustomFields(modulesIds);

            foreach (string fieldName in _CustomFieldIds.Keys)
            {
                GroupParamsRewrite toAdd = new GroupParamsRewrite(glbCustomFieldPrefix + fieldName, desc, RewriteType.SubPath, UrlParam.FromSyntax("propertyid"));
                toAdd.UrlParams[UrlParam.FromSyntax("propertyid")] = ParamNature.NonExclusive | ParamNature.Mandatory;
                toReturn.Add(toAdd);
            }

            return toReturn;

        }


        private void FillCustomFields(List<int> modulesIds = null)
        {
            int mDefId = NukeHelper.GetModuleDefIdByModuleName(glbDesktopModuleName);
            if (mDefId != -1)
            {
                ArrayList modules = null;
                List<CustomFieldInfo> customFields = default(List<CustomFieldInfo>);

                if (modulesIds == null)
                {
                    string moduleDefFriendlyName = ModuleDefinitionController.GetModuleDefinitionByID(mDefId).FriendlyName;
                    modules = NukeHelper.ModuleController.GetModulesByDefinition(NukeHelper.PortalId, moduleDefFriendlyName);


                    foreach (ModuleInfo propModule in modules)
                    {
                        try
                        {
                            customFields = _CustomFieldController.List(propModule.ModuleID, true);
                            foreach (CustomFieldInfo customField in customFields)
                            {
                                if (_CustomFieldIds.ContainsKey(customField.Name.ToLowerInvariant()))
                                {
                                    _CustomFieldIds[customField.Name.ToLowerInvariant()].Add(customField);
                                }
                                else
                                {
                                    List<CustomFieldInfo> objList = new List<CustomFieldInfo>();
                                    objList.Add(customField);
                                    _CustomFieldIds[customField.Name.ToLowerInvariant()] = objList;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
                        }

                    }
                }
                else
                {
                    foreach (int moduleId in modulesIds)
                    {
                        customFields = _CustomFieldController.List(moduleId, true);
                        foreach (CustomFieldInfo customField in customFields)
                        {
                            if (_CustomFieldIds.ContainsKey(customField.Name.ToLowerInvariant()))
                            {
                                _CustomFieldIds[customField.Name.ToLowerInvariant()].Add(customField);
                            }
                            else
                            {
                                List<CustomFieldInfo> objList = new List<CustomFieldInfo>();
                                objList.Add(customField);
                                _CustomFieldIds[customField.Name.ToLowerInvariant()] = objList;
                            }
                        }
                    }
                }
            }
        }

        GroupRewriteResult IUrlRewriterProvider.RewriteParams(string groupName, RewriteType objRewriteType, Dictionary<UrlParam, string> parameters, FriendlierUrlStrategy behaviour)
        {
            GroupRewriteResult toReturn = new GroupRewriteResult();
            
            if (parameters.Count > 0)
            {
                int propertyId = -1;
                switch (groupName.ToLowerInvariant())
                {
                    case "displayname":
                        propertyId = int.Parse(parameters[UrlParam.FromSyntax("propertyid")], CultureInfo.InvariantCulture);
                        toReturn.RewriteValue = GetPropertyDisplayName(propertyId, behaviour);
                        toReturn.ConsumedParameters[UrlParam.FromSyntax("propertyid")] = true;
                        break;
                    case "papropertytypes":
                        int propertyTypeId = int.Parse(parameters[UrlParam.FromSyntax("propertytypeid")], CultureInfo.InvariantCulture);
                        toReturn.RewriteValue = GetPropertyTypeByPropTypeId(propertyTypeId, behaviour, objRewriteType);
                        toReturn.ConsumedParameters[UrlParam.FromSyntax("propertytypeid")] = true;
                        break;
                    case "patype":
                        propertyId = int.Parse(parameters[UrlParam.FromSyntax("propertyid")], CultureInfo.InvariantCulture);
                        toReturn.RewriteValue = GetPropertyTypeByPropId(propertyId, behaviour, objRewriteType);
                        toReturn.ConsumedParameters[UrlParam.FromSyntax("propertyid")] = true;

                        break;
                    default:
                        propertyId = int.Parse(parameters[UrlParam.FromSyntax("propertyid")], CultureInfo.InvariantCulture);

                        if (groupName.ToLowerInvariant().StartsWith(glbCustomFieldPrefix.ToLowerInvariant()))
                        {
                            string fieldName = groupName.Substring(glbCustomFieldPrefix.Length);
                            toReturn.RewriteValue = GetCustomFieldValue(fieldName, propertyId, behaviour);
                            toReturn.ConsumedParameters[UrlParam.FromSyntax("propertyid")] = true;
                        }
                        else if (groupName.ToLowerInvariant().StartsWith(glbAgentProfilePrefix.ToLowerInvariant()))
                        {
                            string fieldName = groupName.Substring(glbAgentProfilePrefix.Length);
                            UserController uc = new UserController();
                            PropertyInfo prop = _PropertyController.Get(propertyId);
                            UserInfo agent = uc.GetUser(NukeHelper.PortalId, prop.AuthorID);
                            toReturn.RewriteValue = agent.Profile.GetPropertyValue(fieldName);
                            toReturn.ConsumedParameters[UrlParam.FromSyntax("propertyid")] = true;
                        }
                        break;
                }
            }
            return toReturn;
        }

        private string GetPropertyDisplayName(int propertyId, FriendlierUrlStrategy behaviour)
        {
            string toreturn = "";
            PropertyInfo prop = _PropertyController.Get(propertyId);
            if (prop != null && prop.PropertyID != -1)
            {
                toreturn = prop.DisplayName;
            }
            return toreturn;
        }

        private string GetPropertyTypeByPropId(int propertyId, FriendlierUrlStrategy behaviour, RewriteType objRewriteType)
        {

            StringBuilder toReturn = new StringBuilder();

            PropertyInfo prop = _PropertyController.Get(propertyId);
            if (objRewriteType == RewriteType.SubPath)
            {
                PropertyTypeInfo propType = _PropertyTypeController.Get(prop.ModuleID, prop.PropertyTypeID);
                toReturn.Append(this.GetPropertyPath(propType, behaviour, objRewriteType));
            }
            else
            {
                toReturn.Append(prop.PropertyTypeName);
            }

            return toReturn.ToString();

        }

        private string GetPropertyTypeByPropTypeId(int proptypeID, FriendlierUrlStrategy behaviour, RewriteType objRewriteType)
        {

            StringBuilder toReturn = new StringBuilder();

            PropertyTypeInfo propType = this.GetPropertyTypeFromBD(proptypeID);

            if (objRewriteType == RewriteType.SubPath)
            {
                toReturn.Append(this.GetPropertyPath(propType, behaviour, objRewriteType));
            }
            else
            {
                toReturn.Append(propType.Name);
            }

            return toReturn.ToString();

        }

        private List<string> GetPropertyPath(PropertyTypeInfo propType, FriendlierUrlStrategy behaviour, RewriteType objRewriteType)
        {
            List<string> toReturn = null;
            if (propType.ParentID > -1)
            {
                PropertyTypeInfo parentPropType = _PropertyTypeController.Get(propType.ModuleID, propType.ParentID);
                toReturn = GetPropertyPath(parentPropType, behaviour, objRewriteType);
            }
            if (toReturn == null)
            {
                toReturn = new List<string>();
            }
            toReturn.Add(propType.Name);
            return toReturn;
        }

        private PropertyTypeInfo GetPropertyTypeFromBD(int propTypeId)
        {
            PropertyTypeInfo toReturn = default(PropertyTypeInfo);

            SqlConnection sqlConn = new SqlConnection(NukeHelper.DnnConnectionString);
            StringBuilder strQuery = new StringBuilder();
            strQuery.Append("SELECT * From ");
            strQuery.Append(NukeHelper.DnnDatabaseOwner);
            strQuery.Append(".Ventrian_PropertyAgent_PropertyType");
            strQuery.Append(NukeHelper.DnnObjectQualifier);
            strQuery.Append(" WHERE PropertyTypeID = ");
            strQuery.Append(propTypeId);

            SqlCommand sqlQuery = new SqlCommand(strQuery.ToString());
            sqlConn.Open();
            sqlQuery.Connection = sqlConn;
            toReturn = CBO.FillObject<PropertyTypeInfo>(sqlQuery.ExecuteReader());
            sqlConn.Close();
            return toReturn;
        }

        private string GetCustomFieldValue(string fieldName, int propertyId, FriendlierUrlStrategy behaviour)
        {
            string toreturn = "";
            PropertyInfo prop = _PropertyController.Get(propertyId);
            if (prop != null && prop.PropertyID != -1)
            {
                foreach (CustomFieldInfo item in _CustomFieldIds[fieldName.ToLowerInvariant()])
                {
                    if (prop.PropertyList.ContainsKey(item.CustomFieldID))
                    {
                        toreturn = prop.PropertyList[item.CustomFieldID].ToString();
                        break;
                    }
                }

            }
            return toreturn;
        }

        public int GetCategory(System.Collections.Generic.Dictionary<UrlParam, string> parameters)
        {
            int categoryId = -1;
            if (parameters.ContainsKey(UrlParam.FromSyntax("propertyid")))
            {
                int contentId = int.Parse(parameters[UrlParam.FromSyntax("propertyid")], CultureInfo.InvariantCulture);
                PropertyInfo prop = _PropertyController.Get(contentId);

                if (prop != null)
                {
                    ContentController ContentCtrl = new ContentController();
                    List<CategoryInfo> CatList = ContentCtrl.GetContentCategories(prop.ModuleID, contentId);

                    if (CatList != null && CatList.Count > 0)
                    {
                        categoryId = CatList[0].CategoryID;
                    }
                }
            }
            return categoryId;
        }

        public bool IsActive
        {
            get { return DotNetNuke.Framework.Reflection.CreateType("Ventrian.PropertyAgent.PropertyController", true) != null; }
        }
    }
}